2 ==============================================================================
4 This file is part of the JUCE library - "Jules' Utility Class Extensions"
5 Copyright 2004-11 by Raw Material Software Ltd.
7 ------------------------------------------------------------------------------
9 JUCE can be redistributed and/or modified under the terms of the GNU General
10 Public License (Version 2), as published by the Free Software Foundation.
11 A copy of the license is included in the JUCE distribution, or can be found
12 online at www.gnu.org/licenses.
14 JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 ------------------------------------------------------------------------------
20 To release a closed-source product which uses JUCE, commercial licenses are
21 available: visit www.rawmaterialsoftware.com/juce for more information.
23 ==============================================================================
26 #include "../jucer_Headers.h"
27 #include "jucer_ComponentLayoutEditor.h"
28 #include "../model/jucer_ObjectTypes.h"
29 #include "../model/components/jucer_JucerComponentHandler.h"
31 //==============================================================================
32 class SubComponentHolderComp
: public Component
35 SubComponentHolderComp (JucerDocument
& document_
,
36 SnapGridPainter
& grid_
)
37 : document (document_
),
39 dontFillBackground (false)
41 setInterceptsMouseClicks (false, false);
42 setWantsKeyboardFocus (false);
43 setFocusContainer (true);
46 ~SubComponentHolderComp()
50 void paint (Graphics
& g
)
52 if (! dontFillBackground
)
54 PaintRoutine
* const background
= document
.getPaintRoutine (0);
58 background
->fillWithBackground (g
, false);
59 background
->drawElements (g
, Rectangle
<int> (0, 0, getWidth(), getHeight()));
62 grid
.draw (g
, background
);
68 if (! getBounds().isEmpty())
70 int numTimesToTry
= 10;
72 while (--numTimesToTry
>= 0)
74 bool anyCompsMoved
= false;
76 for (int i
= 0; i
< getNumChildComponents(); ++i
)
78 Component
* comp
= getChildComponent (i
);
79 ComponentTypeHandler
* const type
= ComponentTypeHandler::getHandlerFor (*comp
);
83 const Rectangle
<int> newBounds (type
->getComponentPosition (comp
)
84 .getRectangle (Rectangle
<int> (0, 0, getWidth(), getHeight()),
85 document
.getComponentLayout()));
87 anyCompsMoved
= anyCompsMoved
|| (comp
->getBounds() != newBounds
);
88 comp
->setBounds (newBounds
);
92 // repeat this loop until they've all stopped shuffling (might require a few
93 // loops for all the relative positioned comps to settle down)
102 ((ComponentLayoutEditor
*) getParentComponent())->updateOverlayPositions();
105 JucerDocument
& document
;
106 SnapGridPainter
& grid
;
107 bool dontFillBackground
;
110 //==============================================================================
111 ComponentLayoutEditor::ComponentLayoutEditor (JucerDocument
& document_
, ComponentLayout
& layout_
)
112 : document (document_
),
116 setWantsKeyboardFocus (true);
118 addAndMakeVisible (subCompHolder
= new SubComponentHolderComp (document
, grid
));
120 refreshAllComponents();
122 setSize (document
.getInitialWidth(), document
.getInitialHeight());
125 ComponentLayoutEditor::~ComponentLayoutEditor()
127 document
.removeChangeListener (this);
129 removeChildComponent (&lassoComp
);
133 //==============================================================================
134 void ComponentLayoutEditor::visibilityChanged()
136 document
.getUndoManager().beginNewTransaction();
140 refreshAllComponents();
141 document
.addChangeListener (this);
145 document
.removeChangeListener (this);
149 void ComponentLayoutEditor::changeListenerCallback (ChangeBroadcaster
*)
151 refreshAllComponents();
154 void ComponentLayoutEditor::paint (Graphics
& g
)
158 void ComponentLayoutEditor::resized()
160 if (firstResize
&& getWidth() > 0 && getHeight() > 0)
163 refreshAllComponents();
166 subCompHolder
->setBounds (getComponentArea());
167 updateOverlayPositions();
170 const Rectangle
<int> ComponentLayoutEditor::getComponentArea() const
172 if (document
.isFixedSize())
174 return Rectangle
<int> ((getWidth() - document
.getInitialWidth()) / 2,
175 (getHeight() - document
.getInitialHeight()) / 2,
176 document
.getInitialWidth(),
177 document
.getInitialHeight());
181 return Rectangle
<int> (editorEdgeGap
, editorEdgeGap
,
182 getWidth() - editorEdgeGap
* 2,
183 getHeight() - editorEdgeGap
* 2);
187 const Image
ComponentLayoutEditor::createComponentLayerSnapshot() const
189 ((SubComponentHolderComp
*) subCompHolder
)->dontFillBackground
= true;
190 Image im
= subCompHolder
->createComponentSnapshot (Rectangle
<int> (0, 0, subCompHolder
->getWidth(), subCompHolder
->getHeight()));
191 ((SubComponentHolderComp
*) subCompHolder
)->dontFillBackground
= false;
196 void ComponentLayoutEditor::updateOverlayPositions()
198 for (int i
= getNumChildComponents(); --i
>= 0;)
200 ComponentOverlayComponent
* const overlay
= dynamic_cast <ComponentOverlayComponent
*> (getChildComponent (i
));
203 overlay
->updateBoundsToMatchTarget();
207 void ComponentLayoutEditor::refreshAllComponents()
210 for (i
= getNumChildComponents(); --i
>= 0;)
212 ComponentOverlayComponent
* const overlay
= dynamic_cast <ComponentOverlayComponent
*> (getChildComponent (i
));
214 if (overlay
!= 0 && ! layout
.containsComponent (overlay
->target
))
218 for (i
= subCompHolder
->getNumChildComponents(); --i
>= 0;)
220 Component
* const comp
= subCompHolder
->getChildComponent (i
);
222 if (! layout
.containsComponent (comp
))
223 subCompHolder
->removeChildComponent (comp
);
226 Component
* lastComp
= 0;
227 Component
* lastOverlay
= 0;
229 for (i
= layout
.getNumComponents(); --i
>= 0;)
231 Component
* const c
= layout
.getComponent (i
);
232 ComponentOverlayComponent
* overlay
= getOverlayCompFor (c
);
234 bool isNewOverlay
= false;
238 ComponentTypeHandler
* const handler
= ComponentTypeHandler::getHandlerFor (*c
);
239 jassert (handler
!= 0);
241 overlay
= handler
->createOverlayComponent (c
, layout
);
243 addAndMakeVisible (overlay
);
247 if (lastOverlay
!= 0)
248 overlay
->toBehind (lastOverlay
);
250 overlay
->toFront (false);
252 lastOverlay
= overlay
;
254 subCompHolder
->addAndMakeVisible (c
);
257 c
->toBehind (lastComp
);
263 c
->setWantsKeyboardFocus (false);
264 c
->setFocusContainer (true);
267 overlay
->updateBoundsToMatchTarget();
270 if (grid
.updateFromDesign (document
))
271 subCompHolder
->repaint();
273 subCompHolder
->setBounds (getComponentArea());
274 subCompHolder
->resized();
277 void ComponentLayoutEditor::mouseDown (const MouseEvent
& e
)
279 if (e
.mods
.isPopupMenu())
283 m
.addCommandItem (commandManager
, CommandIDs::editCompLayout
);
284 m
.addCommandItem (commandManager
, CommandIDs::editCompGraphics
);
287 for (int i
= 0; i
< ObjectTypes::numComponentTypes
; ++i
)
288 m
.addCommandItem (commandManager
, CommandIDs::newComponentBase
+ i
);
294 addChildComponent (&lassoComp
);
295 lassoComp
.beginLasso (e
, this);
299 void ComponentLayoutEditor::mouseDrag (const MouseEvent
& e
)
301 lassoComp
.toFront (false);
302 lassoComp
.dragLasso (e
);
305 void ComponentLayoutEditor::mouseUp (const MouseEvent
& e
)
307 lassoComp
.endLasso();
308 removeChildComponent (&lassoComp
);
310 if (e
.mouseWasClicked() && ! e
.mods
.isAnyModifierKeyDown())
311 layout
.getSelectedSet().deselectAll();
314 static void moveOrStretch (ComponentLayout
& layout
, int x
, int y
, bool snap
, bool stretch
)
317 layout
.stretchSelectedComps (x
, y
, snap
);
319 layout
.moveSelectedComps (x
, y
, snap
);
322 bool ComponentLayoutEditor::keyPressed (const KeyPress
& key
)
324 const bool snap
= key
.getModifiers().isAltDown();
325 const bool stretch
= key
.getModifiers().isShiftDown();
327 const int amount
= snap
? document
.getSnappingGridSize() + 1
330 if (key
.isKeyCode (KeyPress::rightKey
))
332 moveOrStretch (layout
, amount
, 0, snap
, stretch
);
334 else if (key
.isKeyCode (KeyPress::downKey
))
336 moveOrStretch (layout
, 0,amount
, snap
, stretch
);
338 else if (key
.isKeyCode (KeyPress::leftKey
))
340 moveOrStretch (layout
, -amount
, 0, snap
, stretch
);
342 else if (key
.isKeyCode (KeyPress::upKey
))
344 moveOrStretch (layout
, 0, -amount
, snap
, stretch
);
354 bool ComponentLayoutEditor::isInterestedInFileDrag (const StringArray
& filenames
)
356 const File
f (filenames
[0]);
357 return f
.hasFileExtension (".cpp");
360 void ComponentLayoutEditor::filesDropped (const StringArray
& filenames
, int x
, int y
)
362 const File
f (filenames
[0]);
364 if (f
.hasFileExtension (".cpp"))
366 JucerDocument
* doc
= ObjectTypes::loadDocumentFromFile (f
, false);
372 JucerComponentHandler jucerDocHandler
;
373 layout
.getDocument()->getUndoManager().beginNewTransaction();
375 TestComponent
* newOne
376 = dynamic_cast <TestComponent
*> (layout
.addNewComponent (&jucerDocHandler
,
377 x
- subCompHolder
->getX(),
378 y
- subCompHolder
->getY()));
382 JucerComponentHandler::setJucerComponentFile (*layout
.getDocument(), newOne
, f
.getRelativePathFrom (document
.getFile().getParentDirectory()));
384 layout
.getSelectedSet().selectOnly (newOne
);
387 layout
.getDocument()->getUndoManager().beginNewTransaction();
392 ComponentOverlayComponent
* ComponentLayoutEditor::getOverlayCompFor (Component
* compToFind
) const
394 for (int i
= getNumChildComponents(); --i
>= 0;)
396 ComponentOverlayComponent
* const overlay
= dynamic_cast <ComponentOverlayComponent
*> (getChildComponent (i
));
398 if (overlay
!= 0 && overlay
->target
== compToFind
)
405 void ComponentLayoutEditor::findLassoItemsInArea (Array
<Component
*>& results
, const Rectangle
<int>& area
)
407 const Rectangle
<int> lasso (area
- subCompHolder
->getPosition());
409 for (int i
= 0; i
< subCompHolder
->getNumChildComponents(); ++i
)
411 Component
* c
= subCompHolder
->getChildComponent (i
);
413 if (c
->getBounds().intersects (lasso
))
418 SelectedItemSet
<Component
*>& ComponentLayoutEditor::getLassoSelection()
420 return layout
.getSelectedSet();